package com.mpolicy.dbfile.system.service.impl;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceWrapper;
import com.mpolicy.dbfile.common.constants.ExportConstants;
import com.mpolicy.dbfile.config.datasource.DynamicDataSource;
import com.mpolicy.dbfile.config.datasource.DynamicDataSourceContextHolder;
import com.mpolicy.dbfile.common.enums.DataSourceType;
import com.mpolicy.dbfile.system.domain.ExportCondition;
import com.mpolicy.dbfile.system.domain.Tables;
import com.mpolicy.dbfile.system.mapper.TableMapper;
import com.mpolicy.dbfile.system.service.ITableService;
import com.mpolicy.dbfile.common.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * <p> 实现类 </p>
 *
 * @author : zhaoqiuyue
 * @description :
 * @date : 2019/11/8 16:22
 */
@Slf4j
@Service
public class TableService implements ITableService {

    @Autowired
    private TableMapper tableMapper;
    @Autowired
    private TableToWordUtil tableToWordUtil;
    @Value("${spring.datasource.druid.master.url}")
    private String jdbcUrl;

    @Override
    public void getTableInfo(String tableName) {
        File file = null;
        try {
            List<Tables> tables = null;
            // 1、获取数据库所有表信息(若param传入表名则导出单个表信息)
            String dbName = getMysqlDataBaseName(jdbcUrl);
            tables = tableMapper.getAllTables(dbName, tableName);
            if (CollectionUtils.isEmpty(tables)) {
                throw new RuntimeException("数据库或表信息不存在");
            }
            // 2、生成文件名信息 - 年月日时分秒
            String date = DateTimeUtils.dateFormat(new Date(), DateTimeUtils.PARSE_PATTERNS[12]);
            String docFileName = ExportConstants.FILE_PATH + "\\" + ExportConstants.FILE_NAME + "-" + date + ".docx";

            // 3、调用工具类生成文件
            file = tableToWordUtil.toWord(tables, docFileName, dbName, ExportConstants.FILE_NAME);

            // 4、返回文件地址
            FileUtils.writeFile(file, "数据库设计.docx", ServletUtils.getResponse());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            FileUtils.deleteFile(file);
        }
    }

    /**
     * 重置数据库
     * @throws Exception
     */
    private void resetDruid(String url, String name, String pwd) throws Exception {
        DynamicDataSource dataSource = SpringUtils.getBean("dynamicDataSource");
        Field field = dataSource.getClass().getSuperclass().getDeclaredField("targetDataSources");
        field.setAccessible(true);
        Map map = (HashMap) field.get(dataSource);
        DruidDataSourceWrapper wrapper = (DruidDataSourceWrapper)map.get(DataSourceType.SLAVE.toString());
        Field jdbcUrl =wrapper.getClass().getSuperclass().getSuperclass().getDeclaredField("jdbcUrl");
        Field username =wrapper.getClass().getSuperclass().getSuperclass().getDeclaredField("username");
        Field password =wrapper.getClass().getSuperclass().getSuperclass().getDeclaredField("password");
        Method restartMethod = wrapper.getClass().getSuperclass().getDeclaredMethod("restart");
        Field poolingCount = wrapper.getClass().getSuperclass().getDeclaredField("poolingCount");
        jdbcUrl.setAccessible(true);
        username.setAccessible(true);
        password.setAccessible(true);
        poolingCount.setAccessible(true);
        ReflectUtils.setFieldValue(wrapper, "jdbcUrl", url);
        ReflectUtils.setFieldValue(wrapper, "username", name);
        ReflectUtils.setFieldValue(wrapper, "password", pwd);
        // 一定要清，关系到数据库连接的新建，restart方法没有自动清0，导致restart之后查询获取不到线程
        ReflectUtils.setFieldValue(wrapper, "poolingCount", 0);
        jdbcUrl.setAccessible(false);
        username.setAccessible(false);
        password.setAccessible(false);
        poolingCount.setAccessible(false);
        map.put(DataSourceType.SLAVE.toString(), wrapper);
        ReflectUtils.setFieldValue(dataSource, "targetDataSources", map);
        field.setAccessible(false);
        restartMethod.invoke(wrapper);
    }

    /**
     * 自定义数据库获取表结构
     *
     * @param condition
     * @return
     */
    @Override
    public void getTableInfoWithCustomDb(ExportCondition condition) {
        String oldJdbcUrl = jdbcUrl;
        try {
            resetDruid(condition.getJdbcUrl(), condition.getUsername(), condition.getPassword());
            DynamicDataSourceContextHolder.setDataSourceType(DataSourceType.SLAVE.toString());
            jdbcUrl = condition.getJdbcUrl();
            getTableInfo(null);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            DynamicDataSourceContextHolder.clearDataSourceType();
            jdbcUrl = oldJdbcUrl;
        }
    }

    /**
     * 获取数据库名称
     * @param url
     * @return
     */
    public static String getMysqlDataBaseName(String url) {
        Pattern p = Pattern.compile("jdbc:(?<db>\\w+):.*((//)|@)(?<host>.+):(?<port>\\d+)(/|(;DatabaseName=)|:)(?<dbName>\\w+.+)\\?");
        Matcher m = p.matcher(url);
        if(m.find()) {
            return m.group("dbName");
        }
        return null;
    }
}

